package net.homelinux.chaoswg.io.renga.krypto.operations.type;

import java.math.BigInteger;

import net.homelinux.chaoswg.io.higherorderfunctions.AbstractBinaryFunction;
import net.homelinux.chaoswg.io.higherorderfunctions.BinaryFunction;
import net.homelinux.chaoswg.io.renga.krypto.datatypes.numerical.UnsignedNBit;
import net.homelinux.chaoswg.io.renga.krypto.datatypes.numerical.UnsignedNBitFactory;

public class Merge2 extends AbstractBinaryFunction<UnsignedNBit, UnsignedNBit, UnsignedNBit> implements BinaryFunction<UnsignedNBit, UnsignedNBit, UnsignedNBit> {
    private boolean allOfSameType (final UnsignedNBit... unbs) {
        final Class tmp = unbs[0].getClass();
        
        for (final UnsignedNBit unb : unbs) {
            if (! unb.getClass().equals(tmp)) {
                return false;
            }
        }
        return true;
    }

    public UnsignedNBit apply (final UnsignedNBit unb0, final UnsignedNBit unb1) {
        final UnsignedNBitFactory unbFactory = UnsignedNBitFactory.createUnsignedNBitFactory(); 
        final int toMergeFrom = 2;

        if (allOfSameType(unb0, unb1) && unbFactory.exists(unb0.getN() * toMergeFrom)) {
            BigInteger tmp = new BigInteger("0");

            final BigInteger[] u = { unb0.getValue(), unb1.getValue()}; 

            for (int i = 0; i < toMergeFrom; ++i) {
                tmp = tmp.shiftLeft(unb0.getN());
                tmp = tmp.or(u[i]);
            }

            final UnsignedNBit toReturn = unbFactory.get(toMergeFrom*unb0.getN());
            toReturn.setValue(tmp);
            return toReturn;

        }
        return null;
    }
    
    public String toString () {
        return "Merge from two";
    }
}
